package com.qipay.api.qrcode.controller;

import com.qipay.api.BaseController;
import com.qipay.api.alipay.controller.v1.vo.CpPayAlipayNativeVo;
import com.qipay.api.qq.controller.v1.vo.CpPayQQNativeVo;
import com.qipay.api.wx.controller.v1.vo.CpPayWeiXinNativeVo;
import com.qipay.baas.model.Cp;
import com.qipay.baas.model.CpInfo;
import com.qipay.cp.CpService;
import com.qipay.cp.config.CpAccountStateEnum;
import com.qipay.cpinfo.service.CpInfoService;
import com.qipay.order.service.OrderService;
import com.qipay.pay.AlipayService;
import com.qipay.pay.QQPayService;
import com.qipay.pay.WeiXinPayService;
import com.qipay.pay.entity.CpPayAlipayNativeRequest;
import com.qipay.pay.entity.CpPayQQNativeRequest;
import com.qipay.pay.entity.CpPayWeiXinNativeRequest;
import com.qipay.security.jwt.JWTUser;
import com.qipay.security.sign.service.SignService;
import com.qipay.utils.Result;
import com.qipay.utils.SignSortMD5Utils;
import com.qipay.utils.XmlUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * com.qipay.api.qrcode.controller
 *
 * @author Administrator Ansen
 * @date 2017/10/30
 */
@RestController
@RequestMapping("/common")
public class QRCodePayController extends BaseController {

    protected final Log logger = LogFactory.getLog(this.getClass());

    @Value("${api.response.sign.name}")
    private String sigKey;

    @Autowired
    SignService signService;

    @Autowired
    CpService cpService;

    @Autowired
    CpInfoService cpInfoService;

    @Autowired
    OrderService orderService;

    @Autowired
    WeiXinPayService weiXinPayService;

    @Autowired
    QQPayService qqPayService;

    @Autowired
    AlipayService alipayService;

    @RequestMapping(value = "/cp/pay/qrcode", method = RequestMethod.GET)
    public ModelAndView createQRCode(
            @RequestParam @NotNull String mchid,
            @RequestParam @NotNull String sign,
            HttpServletRequest request
    ) {

        Cp cp = cpService.getOneByAppId(mchid);
        Assert.notNull(cp, "无法找到CP的信息");
        Assert.isTrue(Objects.equals(CpAccountStateEnum.ENABLED.getState(), cp.getAccountState()),
                "该CP还未开启支付或已被禁用");

        Map<String, Object> params = new HashMap<>(2);
        params.put("mchid", mchid);

        String mySign = SignSortMD5Utils.getSign(params, cp.getSecretId(), sigKey);
        if (!StringUtils.equals(sign, mySign)) {
            logger.warn("签名不一致:fromSig:" + sign + ", mysig:" + mySign);
        }
        Assert.isTrue(StringUtils.equals(sign, mySign), "无效的签名信息");

        ModelAndView modelAndView = createModelAndView("cp-qr-pay");
        Map<String, Object> viewParams = new HashMap<>(4);

        modelAndView.addObject("mch_id", cp.getAppId());
        viewParams.put("mch_id", cp.getAppId());

        String outTradeNo = orderService.createOrder();
        modelAndView.addObject("out_trade_no", outTradeNo);
        viewParams.put("out_trade_no", outTradeNo);

        modelAndView.addObject("body", "移动支付");
        viewParams.put("body", "移动支付");

        String nonceStr = String.valueOf(System.currentTimeMillis());
        modelAndView.addObject("nonce_str", nonceStr);
        viewParams.put("nonce_str", nonceStr);

        String viewSign = SignSortMD5Utils.getSign(viewParams, cp.getSecretId());
        modelAndView.addObject("sign", viewSign);

        CpInfo cpInfo = cpInfoService.get(cp.getId());
        Assert.notNull(cpInfo, "无法找到CP的信息");

        modelAndView.addObject("mch_name", cpInfo.getName());

        return modelAndView;
    }

    @RequestMapping(value = "/cp/pay/qrcode", method = RequestMethod.POST,
            produces = "application/json;chartset=utf-8")
    public Result<String> cpQrcodePay(
            @RequestParam("mch_id") @NotNull String mchid,
            @RequestParam("out_trade_no") @NotNull String outTradeNo,
            @RequestParam("body") @NotNull String body,
            @RequestParam("nonce_str") @NotNull String nonceStr,
            @RequestParam("sign") @NotNull String sign,
            @RequestParam("total_fee") @NotNull String strTotalFee,
            @RequestParam("mark") String mark,
            HttpServletRequest request
    ) {

        Result<String> result = new Result<>();

        Cp cp = cpService.getOneByAppId(mchid);
        if (cp == null || !Objects.equals(CpAccountStateEnum.ENABLED.getState(), cp.getAccountState())) {
            result.setCode(0);
            result.setMsg("该CP还未开启支付或已被禁用");
            return result;
        }

        BigDecimal totalFee = new BigDecimal(strTotalFee);
        if (totalFee.doubleValue() <= 0) {
            result.setCode(0);
            result.setMsg("请输入正确的付款金额");
            return result;
        }

        Map<String, Object> params = new HashMap<>(2);
        params.put("mch_id", mchid);
        params.put("out_trade_no", outTradeNo);
        params.put("body", body);
        params.put("nonce_str", nonceStr);

        String mySign = SignSortMD5Utils.getSign(params, cp.getSecretId(), sigKey);
        if (!StringUtils.equals(sign, mySign)) {
            logger.warn("签名不一致:fromSig:" + sign + ", mysig:" + mySign);
            result.setCode(0);
            result.setMsg("无效的签名信息");
            return result;
        }

        params.put("nonce_str", String.valueOf(System.currentTimeMillis()));
        params.put("total_fee", totalFee.multiply(new BigDecimal(100)).intValue());
        params.put("mch_create_ip", cp.getIp());
        params.put("notify_url", "none");
        if (StringUtils.isNotBlank(mark)) {
            params.put("attach", mark);
        }

        JWTUser user = new JWTUser(cp.getId(), cp.getAppId(), cp.getSecretId(), cp.getCreateTime(), cp.getSecretId());

        String url = null;
        String ua = request.getHeader("user-agent").toLowerCase();
        if (ua.indexOf("micromessenger") > 0) {// 是微信浏览器
            url = getWeixinPayUrl(params, user);
        } else if (ua.indexOf("alipayclient") > 0) {// 是微信浏览器
            url = getAlipayPayUrl(params, user);
        } else if (ua.indexOf("qq") > 0) {// 是微信浏览器
            url = getQQPayUrl(params, user);
        }

        url = "weixin://wxpay/bizpayurl?pr=vY7keN1";

        if (StringUtils.isBlank(url)) {
            result.setCode(0);
            result.setMsg("请使用微信、支付宝、QQ钱包进行扫码支付");
            return result;
        }
        result.setCode(1);
        result.setData(url);
        return result;
    }

    private String getWeixinPayUrl(Map<String, Object> params, JWTUser user) {

        CpPayWeiXinNativeVo vo = null;
        try {
            vo = (CpPayWeiXinNativeVo) XmlUtils.mapToBean(
                    params, CpPayWeiXinNativeVo.class);

            CpPayWeiXinNativeRequest bean = new CpPayWeiXinNativeRequest();
            BeanUtils.copyProperties(vo, bean);

            Map<String, Object> result = weiXinPayService.payWeixinNative(bean, user);

            Assert.notNull(result, "CP固定二维码扫码，微信支付请求接口失败");
            Assert.isTrue(result.containsKey("code_url"), "CP固定二维码扫码，微信支付请求接口失败");
            Assert.notNull(result.get("code_url"), "CP固定二维码扫码，微信支付请求接口失败");

            return result.get("code_url").toString();
        } catch (Exception e) {
            logger.error(e.toString());
            return null;
        }
    }

    private String getAlipayPayUrl(Map<String, Object> params, JWTUser user) {
        CpPayAlipayNativeVo vo = null;
        try {
            vo = (CpPayAlipayNativeVo) XmlUtils.mapToBean(
                    params, CpPayAlipayNativeVo.class);

            CpPayAlipayNativeRequest bean = new CpPayAlipayNativeRequest();
            BeanUtils.copyProperties(vo, bean);

            Map<String, Object> result = alipayService.payNative(bean, user);

            Assert.notNull(result, "CP固定二维码扫码，支付宝支付请求接口失败");
            Assert.isTrue(result.containsKey("code_url"), "CP固定二维码扫码，支付宝支付请求接口失败");
            Assert.notNull(result.get("code_url"), "CP固定二维码扫码，支付宝支付请求接口失败");

            return result.get("code_url").toString();
        } catch (Exception e) {
            logger.error(e.toString());
            return null;
        }
    }

    private String getQQPayUrl(Map<String, Object> params, JWTUser user) {
        CpPayQQNativeVo vo = null;
        try {
            vo = (CpPayQQNativeVo) XmlUtils.mapToBean(
                    params, CpPayQQNativeVo.class);

            CpPayQQNativeRequest bean = new CpPayQQNativeRequest();
            BeanUtils.copyProperties(vo, bean);

            Map<String, Object> result = qqPayService.payQQNative(bean, user);

            Assert.notNull(result, "CP固定二维码扫码，QQ支付请求接口失败");
            Assert.isTrue(result.containsKey("code_url"), "CP固定二维码扫码，QQ支付请求接口失败");
            Assert.notNull(result.get("code_url"), "CP固定二维码扫码，QQ支付请求接口失败");

            return result.get("code_url").toString();
        } catch (Exception e) {
            logger.error(e.toString());
            return null;
        }
    }

}
